/*
 * Copyright 2012 Marsrutai.lt
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package lt.marsrutai.mobile.android.fragment.task;

import lt.marsrutai.mobile.android.MarsrutaiLTApp;
import lt.marsrutai.mobile.android.activity.intent.TaskIntentHolder;
import lt.marsrutai.mobile.android.task.NotifyingAsyncTask;
import lt.marsrutai.mobile.android.task.NotifyingAsyncTask.AsynTaskHandler;
import lt.marsrutai.mobile.android.util.ActivityUtils;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.content.LocalBroadcastManager;

/**
 * Fragment which hosts an async task. It's main purpose is to preserve the task
 * when screen orientation changes. Additionally it represents task's progress
 * changes with an alert dialog, and informs the target fragment when the task
 * completes.
 * 
 * @author Justas
 * 
 * @param <Params> Params of the hosted task
 * @param <Progress> Progress of the hosted task
 * @param <Result> Result of the hosted task
 * @see NotifyingAsyncTask
 */
public class TaskDialogFragment<Params, Progress, Result> extends DialogFragment implements AsynTaskHandler<Progress> {
    
    private NotifyingAsyncTask<Params, Progress, Result> hostedTask;
    private Params[] params;

    private ProgressDialog progressDialog;

    public void setTask(NotifyingAsyncTask<Params, Progress, Result> task, Params... params) {
        hostedTask = task;
        this.params = params;

        // inject this fragment to the managed task, to receive callbacks
        hostedTask.setCallback(this);
    }
    
    public NotifyingAsyncTask<Params, Progress, Result> getTask() {
        return hostedTask;
    }
    
    @Override
    public ProgressDialog onCreateDialog(Bundle savedInstanceState) {
        progressDialog = new ProgressDialog(getActivity());
        progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
        progressDialog.setCancelable(true);
        progressDialog.setIndeterminate(true);
        return progressDialog;
    }
    
    @Override
    public void onCancel(DialogInterface dialog) {
        super.onCancel(dialog);
        
        // Cancel the managed task, since the dialog is dismissed
        if (hostedTask != null) {
            hostedTask.cancel(false);
        }
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        params = getParams();
        
        /*
         * Retain this instance so it isn't destroyed when MainActivity and
         * MainFragment change configuration.
         */
        setRetainInstance(true);
        
        if (hostedTask != null) {
            hostedTask.execute(params);
        }
    }

    @Override
    public void onDestroyView() {
        // prevent cancellation on rotation
        if (getDialog() != null && getRetainInstance()) {
            getDialog().setDismissMessage(null);
        }
        super.onDestroyView();
    }

    @Override
    public void onDismiss(DialogInterface dialog) {
        super.onDismiss(dialog);

        // Cancel the managed task, since the dialog is dismissed
        if (hostedTask != null) {
            hostedTask.cancel(false);
        }
    }

    @Override
    public void onResume() {
        super.onResume();

        /*
         * has the task been finished while we weren't in this activity? If it
         * was - dismiss the dialog
         */
        if (hostedTask == null) {
            dismiss();
        }
    }

    @Override
    public void onProgressUpdate(Progress... progress) {
        
    }

    @Override
    public void onFinished(Intent result) {
        completeHandling(result);
    }

    @Override
    public void onCancelled(Intent result) {
        completeHandling(result);
    }

    protected Params[] getParams() {
        return null;
    }

    protected void completeHandling(Intent result) {
        /*
         * must check whether the fragment is "resumed" before dismissing the
         * dialog and the fragment
         */
        if (isResumed()) {
            dismiss();
        }

        /*
         * If this fragment isn't "resumed", setting the task to null will allow
         * us to dismiss it in onResume().
         */
        hostedTask = null;

        LocalBroadcastManager.getInstance(MarsrutaiLTApp.getContext()).sendBroadcast(result);
    }

    /**
     * Checks whether provided task fragment managing an active task
     * 
     * @param taskFragment
     * @return
     */
    public static boolean isActive(TaskDialogFragment<?, ?, ?> taskFragment) {
        return taskFragment != null && taskFragment.getTask() != null;
    }
    
    /**
     * Instantiates a task fragment with the provided task params and adds it to the activity.
     * 
     * @param fragmentManager
     * @param taskFragmentClass
     * @param tag
     * @param params
     */
    public static <T extends Parcelable> void download(FragmentManager fragmentManager, Class<? extends TaskDialogFragment<?, ?, ?>> taskFragmentClass, String tag, T... params) {
        TaskIntentHolder intentHolder = new TaskIntentHolder(new Bundle());
        intentHolder.setParams(params);
        
        ActivityUtils.addFragment(fragmentManager, taskFragmentClass, tag, intentHolder.getIntent().getExtras());
    }
}
